---
description: Manage subscriptions on Postgres with Hasura
keywords:
  - hasura
  - docs
  - postgres
  - subscription
slug: index
---

# Postgres: GraphQL Subscriptions

## Introduction

A GraphQL subscription is essentially a query where the client receives an update whenever the value of any field
changes upstream.

Subscriptions are supported for all kinds of queries. All the concepts of [queries](/queries/postgres/index.mdx) hold
true for subscriptions as well.

:::info Postgres Compatibility

Hasura works with most [Postgres compatible flavours](/databases/postgres/index.mdx#postgres-compatible-flavors).

:::

:::info Single subscription in each query caveat

Hasura follows the [GraphQL spec](https://graphql.github.io/graphql-spec/June2018/#sec-Single-root-field) which allows
for only one root field in a subscription. You also cannot execute multiple separate subscriptions in one query. To
have multiple subscriptions running at the same time they must be in separate queries.

:::

## Types of subscriptions

### Live queries

A live query subscription will return the **latest result** of the query being made and not necessarily all the individual
events leading up to the result. By default, updates are delivered to clients every **1 sec**.

See more details [here](/subscriptions/postgres/livequery/index.mdx).

### Streaming subscriptions

A streaming subscription streams the response according to the cursor input by the user. A streaming subscription is
different from a live query as it sends individual rows at a time and not the entire result set.

See more details [here](/subscriptions/postgres/streaming/index.mdx).

### Live query vs streaming subscriptions

Suppose we need to display the messages of a group chat on a page, this can be done either via live queries or streaming
subscriptions. Let's see how they can be used and how they differ from each other.

1. Using **live query**

   With live query, we'll make the following query:

   ```graphql
   subscription {
     messages(where: { group_id: 1 }, order_by: { created_at: asc }) {
       id
       sender
       receiver
       content
       created_at
       edited_at
     }
   }
   ```

   The initial response for this subscription will be all the messages of the group. Let's say the initial response
   contained 100 messages. Now, if there is one more message sent to the group, then all 101 messages will be sent in a
   new response.

2. Using **streaming subscriptions**

   With streaming subscriptions, we'll make the following query:

   ```graphql
   subscription {
     messages_stream(where: { group_id: 1 }, cursor: { initial_value: { created_at: now } }, batch_size: 10) {
       id
       sender
       receiver
       content
       created_at
       edited_at
     }
   }
   ```

   Here, we'll start getting all messages of the group in batches given by `batch_size` with `created_at` greater than
   `now`.

   Following the example of the live query, if we have 100 messages corresponding to the group and only 5 messages with
   `created_at` greater than the current value of the cursor maintained by the cursor, then we will get only the 5
   messages.

The experimental feature flag
[`remove_empty_subscription_responses`](/deployment/graphql-engine-flags/reference.mdx#experimental-features)
can be used to reduce network overhead for projects making heavy use of streaming subscriptions where responses are often
empty by only returning non-empty result sets. Note that for _streaming_ subscriptions this shouldn't result in any
observable change from the subscriber's point of view, but for live queries `null` and `[]` will **never be returned**
which means the subscriber won't receive an initial empty result, for instance, or won't be able to detect when a
query goes from returning a certain result to returning no result(s).

## Communication protocol

Hasura GraphQL Engine uses the
[GraphQL over WebSocket Protocol](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md)
by the [apollographql/subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) library
and the [GraphQL over WebSocket Protocol](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) by the
[graphql-ws](https://github.com/enisdenjo/graphql-ws) library for sending and receiving events. The GraphQL Engine uses
the `Sec-WebSocket-Protocol` header to determine the communication protocol that'll be used. By default, the GraphQL
engine will use the `apollographql/subscriptions-transport-ws` protocol.

:::info Setting headers for subscriptions with Apollo client

If you are using Apollo Client, headers can be passed to a subscription by setting `connectionParams` while
[creating the wsLink](https://www.apollographql.com/docs/react/data/subscriptions/#client-setup):

```js {6-8}
// Create a WebSocket link:
const wsLink = new WebSocketLink({
  uri: `<graphql-endpoint>`,
  options: {
    reconnect: true,
    connectionParams: {
      headers: {headers-object}
    }
  }
});
```

See [this](https://www.apollographql.com/docs/react/data/subscriptions/#authentication-over-websocket) for more info on
using `connectionParams`.

:::

## Cookies and WebSockets

The Hasura GraphQL Engine will read cookies sent by the browser when initiating a WebSocket connection. The browser will
send the cookie only if it is a secure cookie (`secure` flag in the cookie) and if the cookie has a `HttpOnly` flag.

Hasura will read this cookie and use it as headers when resolving authorization (i.e. when resolving the auth webhook).

### Cookies, WebSockets and CORS

As browsers don't enforce Same Origin Policy (SOP) for websockets, the Hasura server enforces the CORS rules when
accepting the websocket connection.

It uses the provided CORS configuration (as per
[Configure CORS](/deployment/graphql-engine-flags/config-examples.mdx#configure-cors)).

1.  When it is `*`, the cookie is read and the CORS check is not enforced.
2.  When there are explicit domains, the cookie will only be read if the request originates from one of the listed
    domains.
3.  If CORS is disabled, the default behavior is that the cookie won't be read (because of potential security issues).
    To override the behavior, you can use the flag `--ws-read-cookie` or the environment variable
    `HASURA_GRAPHQL_WS_READ_COOKIE`. See
    [GraphQL Engine server config reference](/deployment/graphql-engine-flags/reference.mdx) for the setting.
